﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Web.Routing;
using System.Web.Mvc;
using System.Resources;
using System.Collections;
using System.Web.UI;

using ERPStore.Localization.Html;
using ERPStore.Web.Routing;
using ERPStore.Web.Extensions;

using CloudSoft.Extensions;

namespace ERPStore.Localization.Services
{
	public class LocalizationService : ERPStore.Services.ILocalizationService
	{
		private static object m_Lock = new object();
		private string[] m_languageList;
		private string m_Token;
		private string m_ResourcesPath;

		public LocalizationService(ERPStore.Logging.ILogger logger
			, Repositories.ILocalizationRepository localizationRepository)
		{
			this.Logger = logger;
			this.LocalizationRepository = localizationRepository;
		}

		protected ERPStore.Logging.ILogger Logger { get; private set; }

		protected Repositories.ILocalizationRepository LocalizationRepository { get; private set; }

		#region ILocalizationService Members

		public bool Enabled
		{
			get
			{
				return true;
			}
		}

		public string Token
		{
			get
			{
				if (m_Token == null)
				{
					m_Token = Configuration.ConfigurationSettings.AppSettings["token"];
				}
				return m_Token;
			}
		}

		public IEnumerable<string> SupportedLanguageList
		{
			get
			{
				if (m_languageList == null)
				{
					m_languageList = Configuration.ConfigurationSettings.AppSettings["supportedLanguageList"].Split(',');
				}
				return m_languageList;
			}
		}

		public string ResourcesPath
		{
			get
			{
				if (m_ResourcesPath == null)
				{
					m_ResourcesPath = Configuration.ConfigurationSettings.AppSettings["resourcePath"];
				}
				return m_ResourcesPath;
			}
		}

		/// <summary>
		/// Gets the content localization.
		/// </summary>
		/// <param name="path">The path.</param>
		/// <param name="key">The key.</param>
		/// <returns></returns>
		public string GetLocalizedContent(string path, string language, string token, string key, string defaultContent, ERPStore.Models.LocalizedContentType contentType)
		{
			var result = defaultContent;

			path = path.ToLower().Replace("~/views", "").Trim('\\');
			var fileName = System.IO.Path.Combine(ResourcesPath, path.Trim('/').Replace('/', '\\'));
			fileName = string.Format("{0}.{1}.resx", fileName, language);

			if (System.IO.File.Exists(fileName))
			{
				var resourceReader = new ResXResourceReader(fileName);
				var item = resourceReader.Cast<DictionaryEntry>().FirstOrDefault(i => i.Key.Equals(key));
				if (item.Key != null)
				{
					result = (string)item.Value;
				}
			}

			if (token == Token)
			{
				if (contentType == ERPStore.Models.LocalizedContentType.Label)
				{
					var span = new TagBuilder("span");
					span.MergeAttribute("rel", string.Format("{0},{1}", key, path));
					span.MergeAttribute("class", "translate");
					span.SetInnerText(result);
					result = span.ToString(TagRenderMode.Normal);
				}
				else if (contentType == ERPStore.Models.LocalizedContentType.Attribute)
				{
					result = "translate:" + result;
				}
			}


			return result;
		}

		/// <summary>
		/// Sauvegarde une liste de traduction.
		/// 
		/// le principe est de sauvegarder un fichier par langue pour une page ou un controle donné
		/// 
		/// par exemple si le path est :
		/// 
		/// /views/home/index.aspx
		/// 
		/// la liste des traductions est fr, en alors, il y a creation ou append de 2 fichiers
		/// 
		/// /views/home/index.aspx.fr.resx
		/// /views/home/index.aspx.en.resx
		/// 
		/// </summary>
		/// <param name="list">The list.</param>
		public void Save(string path, string language, string key, string value)
		{
			var fileName = System.IO.Path.Combine(ResourcesPath, path.Trim('/').Replace('/', '\\'));
			fileName = string.Format("{0}.{1}.resx", fileName, language);
			var tempFileName = fileName + ".temp";
			using (var resourceWriter = new ResXResourceWriter(tempFileName))
			{
				if (System.IO.File.Exists(fileName))
				{
					using (var resourceReader = new ResXResourceReader(fileName))
					{
						foreach (DictionaryEntry entry in resourceReader)
						{
							var entryKey = entry.Key as string;
							if (!key.Equals(entryKey))
							{
								resourceWriter.AddResource(entryKey, entry.Value);
							}
						}
					}
				}
				else
				{
					CreateFolders(m_ResourcesPath, fileName.ToLower().Replace(m_ResourcesPath.ToLower(), ""));
				}
				resourceWriter.AddResource(key, value);
				resourceWriter.Close();
			}
			System.IO.File.Copy(tempFileName, fileName, true);
			System.IO.File.Delete(tempFileName);
		}

		public Dictionary<int, IEnumerable<ERPStore.Models.EntityLocalization>> GetLocalizationByEntityIdList(string entityName, IEnumerable<int> entityIdList)
		{
			return LocalizationRepository.GetLocalizationByEntitIdList(entityName, entityIdList);
		}

		public IEnumerable<ERPStore.Models.EntityLocalization> GetLocalizationByEntityId(string entityName, int entityId)
		{
			return LocalizationRepository.GetLocalizationByEntityId(entityName, entityId);
		}

		public string GetCurrentLanguage(System.Web.HttpContextBase context)
		{
            return (string)context.Items["language"];
		}

		#endregion

		private void CreateFolders(string root, string path)
		{
			path = path.Trim('\\').Trim('/');
			// Il existe un sub folder
			if (path.IndexOf(@"\") != -1)
			{
				string[] folders = path.Split('\\');
				for (int i = 0; i < folders.Length - 1; i++)
				{
					string folder = folders[i];
					root = root + @"\" + folder;
					if (!System.IO.Directory.Exists(root))
					{
						System.IO.Directory.CreateDirectory(root);
					}
				}
			}

		}

		internal void LocalizeRoutes(RouteCollection routes)
		{
			var fileName = Configuration.ConfigurationSettings.AppSettings["localizedRoutesFileName"];

			if (fileName.StartsWith(@".\"))
			{
				fileName = System.IO.Path.Combine(GlobalConfiguration.Configuration.Settings.PhysicalPath, fileName.Replace(@".\", ""));
			}

			var xml = new System.Xml.XmlDocument();
			xml.Load(fileName);

			var nodes = from node in xml.SelectNodes("//routes/route").Cast<System.Xml.XmlNode>()
						from language in node.SelectNodes("add").Cast<System.Xml.XmlNode>()
						let name = Convert.ToString(node.Attributes["name"].InnerText)
						select new
						{
							Name = name,
							Language = Convert.ToString(language.Attributes["language"].InnerText),
							Url = Convert.ToString(language.Attributes["url"].InnerText),
						};

			foreach (var item in nodes)
			{
				var route = routes.GetByName(item.Name);
				if (route == null)
				{
					continue;
				}

				var localizedName = string.Format("{0}-{1}", item.Name, item.Language);
				var defaults = new RouteValueDictionary();
				foreach (var rvi in route.Defaults)
				{
					defaults.Add(rvi.Key, rvi.Value);
				}
				var constraints = new RouteValueDictionary(route.Constraints);
				foreach (var rvi in route.Constraints)
				{
                    if (!constraints.ContainsKey(rvi.Key))
                    {
                        constraints.Add(rvi.Key, rvi.Value);
                    }
				}
				var localizedRoute = routes.CreateERPStoreRoute(localizedName, item.Url, defaults, constraints, null);
				localizedRoute.Defaults["language"] = item.Language;

				var index = routes.IndexOf(route);
				routes.InsertRoute(index + 1,localizedName, localizedRoute);
			}
		}

	}
}
